/*
 * Copyright (c) 2009, EzWare
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions 
 * are met:
 * 
 * Redistributions of source code must retain the above copyright notice, 
 * this list of conditions and the following disclaimer.Redistributions 
 * in binary form must reproduce the above copyright notice, this list of 
 * conditions and the following disclaimer in the documentation and/or 
 * other materials provided with the distribution.Neither the name of the 
 * EzWare nor the names of its contributors may be used to endorse or 
 * promote products derived from this software without specific prior 
 * written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 * POSSIBILITY OF SUCH DAMAGE.
 * 
 */

package org.chaser.action

import scala.swing._

import scala.collection.mutable._

import javax.swing.JPopupMenu
import javax.swing.JToggleButton

import org.chaser.action._
import org.chaser.tools._


class ActionContainerBuilder {

   private val cmptCounts   = new HashMap[Component,Int]()
   private val buttonGroups = new HashMap[Component,ButtonGroup]()
   val states               = new SeparatorStates();
   
   
   private def setupToolBarButton( btn: javax.swing.AbstractButton, a: Action ) = {
      if ( btn.getIcon != null ) {
       	  btn.setToolTipText( a.title ) 
       	  btn.setHideActionText(true)
      }
   } 
   
   private def clearState() = {
     cmptCounts.clear();
     buttonGroups.clear();
     states.clear()
   }
   
   def buildToolBar[T <: Action]( toolBar: ToolBar, actions: Iterable[T] ): ToolBar = {
     
     clearState();
     toolBar.peer.removeAll;
     
     actions.foreach( a => 

	      a match {
	        
	      	case null | Action.NoAction => toolBar.peer.addSeparator;  
	        case ag: ActionGroup => {
	          val btn = new DropMenuButton( ag )
	          setupToolBarButton(btn.peer, ag)
	          toolBar.add(btn)
            } 
	        case ca: CheckAction => {
	          val btn = new ToggleButton()
	          btn.action = ca
	          setupToolBarButton(btn.peer, ca)
	          toolBar.add(btn)
            }
	        case ra: RadioAction => {
	          val btn = new ToggleButton()
	          btn.action = ra	
           	  getButtonGroup(toolBar).buttons += btn;
              setupToolBarButton(btn.peer, ra)
	          toolBar.add(btn)
            }
	        case _ => {
	          setupToolBarButton(toolBar.peer.add( a.peer ), a)
            }
         
          }
     )
     
     toolBar
     
   }
   
   
    /**
     * Builds menu bar out of action tree 
     */
    def buildMenuBar[T <: Action]( menuBar: scala.swing.MenuBar, actions: Iterable[T] ): scala.swing.MenuBar = {
     
      clearState();
      actions.foreach( a => 

          a match {
            case ia: Iterable[Action] => {
               	val menu = createMenu( menuBar, a.title );
                if ( !ia.isEmpty ) {
                	addActionGroup( menu, "", ia );
                } 
            }
          }
        
      )
      
      menuBar
      
    }
    
     /**
     * Builds menu bar out of action tree 
     */
    def buildPopupMenu[T <: Action]( popupMenu: PopupMenu, actions: Iterable[T] ): PopupMenu = {
      clearState();
      actions.foreach( a => addAction( popupMenu, a ))
      popupMenu
    }
    
  
    /**
     * Builds menu out of action tree
     */
    def buildMenu[T <: Action]( menu: Menu, actions: Iterable[T] ): Menu = {
       clearState();
       actions.foreach( a => addAction( menu, a ));                  
       menu
    }
    
    
   /*---------------------------------------------------------------------------------*/ 
    

   def addSeparatorTo( menu: SequentialContainer.Wrapper ) {
      
       if ( cmptCounts.getOrElse( menu, 0 ) > 0  && (!states.is(menu, Separator.CannotHave)) )  {
         
          menu match {
            case m: Menu      => m.peer.addSeparator
            case m: PopupMenu => m.peer.addSeparator
          }
         
          states.set( menu, Separator.CannotHave )
       } 
    }    
    
    private def createMenu( owner: SequentialContainer.Wrapper, title: String ): Menu = {
        val newMenu =  new Menu( title ) 
        owner.contents += newMenu
        incCount(owner)
        newMenu
    }
    
    
    private def addAction( menu: SequentialContainer.Wrapper, action: Action ) {
      
       action match {
         case ia: Iterable[Action] => addActionGroup( menu, action.title, ia )
         case null | Action.NoAction => addSeparatorTo(menu)  
         case _  => createMenuItem( menu, action )
       }	
       
    }
    
    private def incCount( c: Component ) {
      cmptCounts.put( c, cmptCounts.getOrElse(c,0) + 1 )
    }
    
    private def getButtonGroup( c: Component ): ButtonGroup = {
       buttonGroups.getOrElseUpdate(c, new ButtonGroup()); 
    }
    
    private def createMenuItem( owner: SequentialContainer.Wrapper, action: Action ) = {

      if ( states.is(owner, Separator.MustHave) ) addSeparatorTo(owner)

      var menuItem: MenuItem = null
      action match {
        case a: CheckAction => menuItem = new CheckMenuItem( a.title )
        case a: RadioAction => {
          menuItem = new RadioMenuItem( a.title )
          getButtonGroup(owner).buttons += menuItem;
        } 
        case _ => menuItem = new MenuItem( action.title )
      } 
      menuItem.action = action
      owner.contents += menuItem;
      
      states.set( owner, Separator.MayHave )
      incCount(owner)
      
    } 
    
    private def addActionGroup( owner: SequentialContainer.Wrapper, title: String, actions: Iterable[Action] ) {
      
        if ( title == null || title.trim.isEmpty ) {
           addSeparatorTo( owner );
           actions.foreach( a => addAction( owner, a ) )
           states.set(owner, Separator.MustHave);
        } else {
           val newMenu = createMenu( owner, title ) 
    	   actions.foreach( a => addAction( newMenu, a ) )
        }
        
    }
    
}


